#include <iostream>
#include <thread>
#include <future>
#include <chrono>

int Add(int num1, int num2)
{
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return num1 + num2;
}

int main()
{
    // 第一种方式
    // std::packaged_task<int(int, int)> tsk(Add);
    // std::future<int> fut = tsk.get_future();

    // // packaged_task对象不可拷贝，但是支持移动语义
    // std::thread th1(std::move(tsk), 10, 11);

    // int result = fut.get();
    // std::cout << "结果是：" << result << std::endl;
    // th1.join();

    // 第二种方式
    // 把tsk定义成一个指针，传递到线程中，然后解引用执行
    // 但是如果单纯定义一个指针指向tsk，又会存在指针的生命周期的问题，很有可能出现风险
    // 所以我们在堆上申请一个智能指针
    auto taskptr = std::make_shared<std::packaged_task<int(int, int)>>(Add);
    std::future<int> fut = taskptr->get_future();

    std::thread th1([taskptr]()
                    { (*taskptr)(10, 11); });
    int result = fut.get();
    std::cout << "结果是：" << result << std::endl;
    th1.join();

    return 0;
}

// #include <thread>
// #include <iostream>
// #include <iostream>
// #include <thread>
// using namespace std;
// void thread_1()
// {
//     cout << "子线程1" << endl;
// }
// void thread_2(int x)
// {
//     cout << "x:" << x << endl;
//     cout << "子线程2" << endl;
// }
// int main()
// {
//     thread first(thread_1);       // 开启线程，调用：thread_1()
//     thread second(thread_2, 100); // 开启线程，调用：thread_2(100)
//     // thread third(thread_2,3);//开启第3个线程，共享thread_2函数。
//     std::cout << "主线程\n";

//     first.join(); // 必须说明添加线程的方式
//     second.join();
//     std::cout << "子线程结束.\n"; // 必须join完成
//     return 0;
//}

// #include <iostream> // std::cout
// #include <thread>   // std::thread
// #include <mutex>    // std::mutex
// #include <unistd.h>
// std::mutex mtx; // mutex for critical section

// void print_block(int n, char c)
// {
//     // critical section (exclusive access to std::cout signaled by locking mtx):
//     mtx.lock();
//     for (int i = 0; i < n; ++i)
//     {
//         std::cout << c;
//         fflush(stdout);
//         sleep(1);
//     }
//     std::cout << '\n';
//     mtx.unlock();
// }

// int main()
// {
//     std::thread th1(print_block, 10, '*'); // 线程1：打印*
//     std::thread th2(print_block, 10, '$'); // 线程2：打印$

//     th1.join();
//     th2.join();

//     return 0;
// }
// #include <iostream> // std::cout
// #include <thread>   // std::thread
// #include <mutex>    // std::mutex

// std::mutex mtx_1; // mutex for critical section
// std::mutex mtx_2; // mutex for critical section

// int test_num = 1;

// void print_block_1(int n, char c)
// {
//     // critical section (exclusive access to std::cout signaled by locking mtx):
//     mtx_1.lock();
//     for (int i = 0; i < n; ++i)
//     {
//         // std::cout << c;
//         test_num = 1;
//         std::cout << test_num << std::endl;
//     }
//     std::cout << '\n';
//     mtx_1.unlock();
// }
// void print_block_2(int n, char c)
// {
//     // critical section (exclusive access to std::cout signaled by locking mtx):
//     mtx_2.lock();
//     test_num = 2;
//     for (int i = 0; i < n; ++i)
//     {
//         // std::cout << c;
//         test_num = 2;
//         std::cout << test_num << std::endl;
//     }
//     mtx_2.unlock();
// }

// int main()
// {
//     std::thread th1(print_block_1, 50, '*');
//     std::thread th2(print_block_2, 50, '$');

//     th1.join();
//     th2.join();

//     return 0;
// }
// #include <thread>
// #include <mutex>
// #include <iostream>

// int g_i = 0;
// std::mutex g_i_mutex; // protects g_i，用来保护g_i

// void safe_increment()
// {
//     const std::lock_guard<std::mutex> lock(g_i_mutex);
//     ++g_i;
//     std::cout << std::this_thread::get_id() << ": " << g_i << '\n';
//     // g_i_mutex自动解锁
// }

// int main()
// {
//     std::cout << "main id: " << std::this_thread::get_id() << std::endl;
//     std::cout << "main: " << g_i << '\n';

//     std::thread t1(safe_increment);
//     std::thread t2(safe_increment);

//     t1.join();
//     t2.join();

//     std::cout << "main: " << g_i << '\n';
// }
// #include <iostream>
// using namespace std;
// void Fun(int &x) { cout << "左值引用" << endl; }
// void Fun(const int &x) { cout << "const 左值引用" << endl; }
// void Fun(int &&x) { cout << "右值引用" << endl; }
// void Fun(const int &&x) { cout << "const 右值引用" << endl; }
// // 模板中的&&不代表右值引用，而是万能引用，其既能接收左值又能接收右值。
// // 模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力，
// // 但是引用类型的唯一作用就是限制了接收的类型，后续使用中都退化成了左值，
// // 我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用我们下面学习的完美转发
// template <typename T>
// void PerfectForward(T &&t)
// {
//     Fun(forward<T>(t));
// }
// int main()
// {
//     PerfectForward(10); // 右值
//     int a;
//     PerfectForward(a);            // 左值
//     PerfectForward(std::move(a)); // 右值
//     const int b = 8;
//     PerfectForward(b);            // const 左值
//     PerfectForward(std::move(b)); // const 右值
//     return 0;
// }